
#include "udc.h"
#include "msc.h"
#include "sd_mmc.h"
#include "io_api.h"
#include <stdlib.h>
#include <string.h>
#include "io_mgr.h"

uint8_t str_dsc[64];

uint8_t dev_dsc[] =
{
    0x12,                       //dev_dsc length
    USB_DT_DEVICE,
    0x00, 0x02,                 //usb version
    0x00, 0x00, 0x00,           //class subclass protocol
    USB_DEVICE_EP_CTRL_SIZE,    //ep0 max size
    0xe7, 0x19,                 //vid
    0x11, 0x11,                 //pid
    0x00, 0x01,                 //device version
    VENDOR_STR_IDX,             //index for vendor string
    PRODUCT_STR_IDX,            //index for product string
    SN_STR_IDX,                 //index for SN
    0x01                        //cfg num
};

const uint8_t dev_qual_dsc[] =
{
    0x0a,                       //DevQualDsc length
    USB_DT_DEVICE_QUALIFIER,
    0x00, 0x02,                 //usb version
    0x00, 0x00, 0x00,           //class subclass protocol
    USB_DEVICE_EP_CTRL_SIZE,    //ep0 max size
    0x01,                       //cfg num
    0x00                        //reserved
};

uint8_t cfg_dsc_msc[] =
{
    //config dsc
    0x09,                       //CfgDsc length
    USB_DT_CONFIGURATION,
    32, 0x00,
    0x01,                       //interface num = 1
    0x01,                       //ConfigValue
    0,                          //index for config string
    0x80,                       //bus-powered
    0xfa,                       //max-power
    
    //interface dsc for msc
    0x09,                       //InterfaceDsc length
    USB_DT_INTERFACE,
    0x00,                       //InterfaceValue
    0x00,                       //AlterSetting
    0x02,                       //endpoint num
    MSC_CLASS,                  //class
    MSC_SUBCLASS_TRANSPARENT,   //subclass
    MSC_PROTOCOL_BULK,          //protocol
    0,                          //index for interface string
    
    //endpoint dsc(1)
    0x07,                       //EndpointDsc length
    USB_DT_ENDPOINT,
    MSC_EP_IN,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,                       //max packet lenth 512
    0x00,
    
    //endpoint dsc(2)
    0x07,                       //EndpointDsc length
    USB_DT_ENDPOINT,
    MSC_EP_OUT,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,                       //max packet lenth 512
    0x00
};

const uint8_t cfg_dsc_jpm[] =
{
    //cfg dsc
    0x09,   
    USB_DT_CONFIGURATION,
    64, 0x00,
    0x02,                       //interface num = 2
    0x01,
    CFG_STR_IDX,
    0xc0,
    0x05,

    //interface dsc for iAP2
    0x09,
    USB_DT_INTERFACE,
    0x00,
    0x00,
    0x02,   
    APPLE_DEVICE_CLASS,
    IAP2_SUBCLASS_TRANSPARENT,
    DEFAULT_PROTOCOL,
    INTERFACE0_STR_IDX,
    
    //endpoint dsc for iAP2 IN
    0x07,
    USB_DT_ENDPOINT,
    IAP2_EP_IN,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00,

    //endpoint dsc for iAP2 OUT
    0x07,
    USB_DT_ENDPOINT,
    IAP2_EP_OUT,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00,

    //endpoint dsc for iAP2 interrupt IN
    //0x07,
    //USB_DT_ENDPOINT,
    //INTR_EP_IN,
    //USB_EP_TYPE_INTERRUPT,
    //0x40,
    //0x00,
    //0x06,     //Polling interval in milliseconds
  
    //interface dsc for EA Native AlterSetting0
    0x09,
    USB_DT_INTERFACE,
    0x01,
    0x00,
    0x00,
    APPLE_DEVICE_CLASS,
    IAP2_SUBCLASS_TRANSPARENT,
    NATIVE_PROTOCOL,
    INTERFACE1_STR_IDX,

    //interface dsc for EA Native AlterSetting1
    0x09,
    USB_DT_INTERFACE,
    0x01,
    0x01,
    0x02,
    APPLE_DEVICE_CLASS,
    IAP2_SUBCLASS_TRANSPARENT,
    NATIVE_PROTOCOL,
    INTERFACE1_STR_IDX,
  
    //endpoint dsc for EA Native IN
    0x07,
    USB_DT_ENDPOINT,
    NATIVE_EP_IN,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00,
  
    //endpoint dsc for EA Native OUT
    0x07,
    USB_DT_ENDPOINT,
    NATIVE_EP_OUT,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00
};

const uint8_t cfg_dsc_jpm_iOS6[] =
{
    //cfg dsc
    0x09,   
    USB_DT_CONFIGURATION,
    71, 0x00,
    0x02,                       //interface num = 2
    0x01,
    CFG_STR_IDX,
    0xc0,
    0x05,

    //interface dsc for iAP2
    0x09,
    USB_DT_INTERFACE,
    0x00,
    0x00,
    0x03,   
    APPLE_DEVICE_CLASS,
    IAP2_SUBCLASS_TRANSPARENT,
    DEFAULT_PROTOCOL,
    INTERFACE0_STR_IDX,
    
    //endpoint dsc for iAP2 IN
    0x07,
    USB_DT_ENDPOINT,
    IAP2_EP_IN,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00,

    //endpoint dsc for iAP2 OUT
    0x07,
    USB_DT_ENDPOINT,
    IAP2_EP_OUT,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00,

    //endpoint dsc for iAP2 interrupt IN
    0x07,
    USB_DT_ENDPOINT,
    INTR_EP_IN,
    USB_EP_TYPE_INTERRUPT,
    0x40,
    0x00,
    0x06,     //Polling interval in milliseconds
  
    //interface dsc for EA Native AlterSetting0
    0x09,
    USB_DT_INTERFACE,
    0x01,
    0x00,
    0x00,
    APPLE_DEVICE_CLASS,
    IAP2_SUBCLASS_TRANSPARENT,
    NATIVE_PROTOCOL,
    INTERFACE1_STR_IDX,

    //interface dsc for EA Native AlterSetting1
    0x09,
    USB_DT_INTERFACE,
    0x01,
    0x01,
    0x02,
    APPLE_DEVICE_CLASS,
    IAP2_SUBCLASS_TRANSPARENT,
    NATIVE_PROTOCOL,
    INTERFACE1_STR_IDX,
  
    //endpoint dsc for EA Native IN
    0x07,
    USB_DT_ENDPOINT,
    NATIVE_EP_IN,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00,
  
    //endpoint dsc for EA Native OUT
    0x07,
    USB_DT_ENDPOINT,
    NATIVE_EP_OUT,
    USB_EP_TYPE_BULK,
    0x00,
    0x02,
    0x00
};

const uint8_t default_str_dsc[] =
{
    0x04, USB_DT_STRING, 0x09, 0x04
};

uint8_t g_max_lun = 0;
uint16_t msc_bulk_size = 0;

//for main process ctrl
uint8_t g_msc_start = 0;
uint8_t g_jpm_iap_start = 0;
uint8_t g_jpm_native_start = 0;
uint8_t g_jpm_start_stop_charge = 0;
uint8_t g_jpm_start_mfi = MFI_NO_AUTH;

//void   (*ep4_in_ptr)(void) = NULL;
//void   (*ep3_out_ptr)(void) = NULL;

static uint16_t jpm_make_str_desc(uint8_t *desc, uint8_t *unicode);
static uint8_t jpm_get_strlen(uint8_t *buf);

void usb_device_interrupt(void)
{       
        //received setup-up pkt
        if (Is_udd_endpoint_interrupt(0)) 
        {              
              if(Is_udd_setup_received(0))
              {
                udd_ctrl_setup_received();
                return;
              }
              
        }       

        // ep3 out pkt received
        /*if ((Is_udd_endpoint_interrupt(3)) && (Is_udd_out_received_interrupt_enabled(3)))
        {
            if (Is_udd_out_received(3))
            {                    
                if(ep3_out_ptr != NULL)
                {
                    ep3_out_ptr();                
                }
                else
                {
                    udd_ack_out_received(3);
                    udd_ack_fifocon(3);
                }
                return;
            }
        }*/
  
        // ep4 in pkt sent
        /*if ((Is_udd_endpoint_interrupt(4)) && (Is_udd_in_send_interrupt_enabled(4)))
        {
            if (Is_udd_in_send(4))
            {
                if(ep4_in_ptr != NULL)
                {
                    ep4_in_ptr();
                }

                return;
            }
        }*/

	// USB bus reset detection
	if (Is_udd_reset()) 
        {
            udd_ack_reset();

            // Reset endpoint control
            udd_reset_ep_ctrl();             
            // Reset endpoint control management
            udd_ctrl_init();

            setup_process_ptr = jpm_setup;            
            ex_status.usb_role = USB_RESET;
            return;
	}
        
        if (Is_udd_suspend_interrupt_enabled() && Is_udd_suspend()) 
        {
		otg_unfreeze_clock();
		// The suspend interrupt is automatic acked when a wakeup occur
		udd_disable_suspend_interrupt();
		udd_enable_wake_up_interrupt();
		otg_freeze_clock(); // Mandatory to exit of sleep mode after a wakeup event
		//udd_sleep_mode(false);  // Enter in SUSPEND mode
                
                //led_set_status(LED_3, LED_ON);
                
                return;
            
        }

        if (Is_udd_wake_up_interrupt_enabled() && Is_udd_wake_up()) 
        {
		// Ack wakeup interrupt and enable suspend interrupt
		otg_unfreeze_clock();
		// Check USB clock ready after suspend and eventually sleep USB clock
		while (!Is_otg_clock_usable()) {
			if (Is_udd_suspend()) {
				break; // In case of USB state change in HS
			}
		};
		// The wakeup interrupt is automatic acked when a suspend occur
		udd_disable_wake_up_interrupt();
		udd_enable_suspend_interrupt();
		//udd_sleep_mode(true); // Enter in IDLE mode
                //led_set_status(LED_3, LED_OFF);
                
                return;
        }
        
        if(Is_otg_vbus_transition())
        {
            otg_unfreeze_clock();
            otg_ack_vbus_transition();
            otg_freeze_clock();            
            otg_unfreeze_clock();
            while (!Is_otg_clock_usable());           
            Clr_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_DETACH);           
            UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_EORSTES | UOTGHS_DEVIER_SUSPES | UOTGHS_DEVIER_WAKEUPES;
            udd_ack_reset();
            udd_raise_suspend();
            udd_ack_wake_up();            
            otg_freeze_clock();
            return;
        }
	return;
}

bool jpm_get_string_dsc(void)
{
    //uint8_t i;
    switch(g_setup_req.wValue & 0x00ff)
    {
    case VENDOR_STR_IDX:
        jpm_make_str_desc(str_dsc, USBD_MANUFACTURER_STRING); 
        break;
        
    case PRODUCT_STR_IDX:
        jpm_make_str_desc(str_dsc, USBD_PRODUCT_STRING); 
        break;
        
    case SN_STR_IDX:
         
        //modify_sn_code();
        jpm_make_str_desc(str_dsc, g_modify_code + 4); 
        break;
        
    case CFG_STR_IDX:
        jpm_make_str_desc(str_dsc, USBD_CONFIGURATION_STRING);
        break;
        
    case INTERFACE0_STR_IDX:
        jpm_make_str_desc(str_dsc, USBD_INTERFACE_IAP2_STRING);
        break;
        
    case INTERFACE1_STR_IDX:
        jpm_make_str_desc(str_dsc, USBD_INTERFACE_EA_STRING); 
        break;
          
    case DEFAULT_STR_IDX:
    default:
        ep0_buf_ptr = (uint8_t *)(&(default_str_dsc[0]));  
        return true;
        break;
    }
    ep0_buf_ptr = &(str_dsc[0]);
    return true;
}

uint16_t jpm_get_descriptor(void)
{
    uint16_t dsc_len;
    switch((uint8_t) (g_setup_req.wValue >> 8))
    {
    case USB_DT_DEVICE:
        if(ex_status.ex_power_type == P_SRC_PC)
        {
            set_sn_for_pc();       //for PC, SN string is not valid for better
        }
        else
        {
            set_sn_for_iph();      //for iPhone5, SN must be valid
        }
        ep0_buf_ptr = (uint8_t *)(&(dev_dsc[0]));
        dsc_len = ep0_buf_ptr[0];
        break;
         
    case USB_DT_CONFIGURATION:
        if(ex_status.ex_power_type == P_SRC_PC)
        {
           convert_otherspeed_cfg();     // configuration dsc
           if(Is_udd_full_speed_mode())
           {
               convert_cfg_dsc_fs();  //FS configuration at full-speed
           }
           else
           {
               convert_cfg_dsc_hs();     //HS configuration at high-speed
           }
            
           ep0_buf_ptr = (uint8_t *)(&(cfg_dsc_msc[0]));           
        }
        else
        {
           if(b_iOS6 == true)
           {
              ep0_buf_ptr = (uint8_t *)(&(cfg_dsc_jpm_iOS6[0]));
           }
           else
           {
              ep0_buf_ptr = (uint8_t *)(&(cfg_dsc_jpm[0]));
           }
        }
        dsc_len = ((ep0_buf_ptr[2] & 0x00ff) | ((ep0_buf_ptr[3] << 8) & 0xff00));
        break;
         
    case USB_DT_DEVICE_QUALIFIER:
        ep0_buf_ptr = (uint8_t *)(&(dev_qual_dsc[0]));
        dsc_len = ep0_buf_ptr[0];
        break;
        
    case USB_DT_OTHER_SPEED_CONFIGURATION:
        if(ex_status.ex_power_type == P_SRC_PC)
        {
           convert_cfg_otherspeed();       //other-speed configuration dsc
           if(!Is_udd_full_speed_mode())
           {
               convert_cfg_dsc_fs();      //FS configuration at high-speed
           }
           else
           {
               convert_cfg_dsc_hs();      //HS configuration at full-speed
           }
            
           ep0_buf_ptr = (uint8_t *)(&(cfg_dsc_msc[0]));
        }
        else
        {
           ep0_buf_ptr = NULL;           //other-speed is not to used for iPhone5
           return 0;
        }
        dsc_len = ((ep0_buf_ptr[1] & 0x00ff) | ((ep0_buf_ptr[2] << 8) & 0xff00));
        break;
        
    case USB_DT_STRING:
        if(!jpm_get_string_dsc())
        {
            ep0_buf_ptr = NULL;
            return 0;
        }
        dsc_len = ep0_buf_ptr[0];
        break;
         
    default:
        ep0_buf_ptr = NULL;
        return 0;
        break;
    }
    
    if(dsc_len > g_setup_req.wLength)
    {
        dsc_len = g_setup_req.wLength;
    }
    return dsc_len;
}

void init_msc(void)
{
    if(Is_udd_full_speed_mode())
    {
        msc_bulk_size = FS_BULK_EP_SIZE;  
    }
    
    else
    {
        msc_bulk_size = HS_BULK_EP_SIZE;
    }
    
    udd_set_ep((MSC_EP_IN&0x0f), 1, USB_EP_TYPE_BULK, msc_bulk_size);
    udd_set_ep((MSC_EP_OUT&0x0f), 0, USB_EP_TYPE_BULK, msc_bulk_size);
    udd_ack_out_received(MSC_EP_OUT&0x0f);
 
    ping_pong.b_ping_flag = true;
    ping_pong.p_ping_buf_ptr = &(msc_bulk_buffer[0]);
    ping_pong.p_pong_buf_ptr = &(msc_bulk_buffer[PINGPONG_BUFFER_SIZE]);
    
    g_msc_start = 1;
}

void init_jpm(void)
{    
    udd_set_ep((IAP2_EP_IN&0x0f), 1, USB_EP_TYPE_BULK, IAP2_PACKET_LEN);
    udd_set_ep((IAP2_EP_OUT&0x0f), 0, USB_EP_TYPE_BULK, IAP2_PACKET_LEN);
    //udd_set_ep((INTR_EP_IN&0x0f), 1, USB_EP_TYPE_INTERRUPT, INTR_IN_EP_SIZE);
        
    udd_ack_out_received(IAP2_EP_OUT&0x0f);    
    //udd_enable_endpoint_interrupt((IAP2_EP_OUT&0x0f));
    //udd_enable_out_received_interrupt((IAP2_EP_OUT&0x0f));
    
    g_jpm_start_mfi = MFI_AUTH_START;
    g_jpm_iap_start = 1;       
}

void init_jpm_iOS6(void)
{
    udd_set_ep((IAP2_EP_IN&0x0f), 1, USB_EP_TYPE_BULK, IAP2_PACKET_LEN);
    udd_set_ep((IAP2_EP_OUT&0x0f), 0, USB_EP_TYPE_BULK, IAP2_PACKET_LEN);
    udd_set_ep((INTR_EP_IN&0x0f), 1, USB_EP_TYPE_INTERRUPT, INTR_IN_EP_SIZE);
        
    udd_ack_out_received(IAP2_EP_OUT&0x0f);    
    //udd_enable_endpoint_interrupt((IAP2_EP_OUT&0x0f));
    //udd_enable_out_received_interrupt((IAP2_EP_OUT&0x0f));
    
    g_jpm_start_mfi = MFI_AUTH_START;
    g_jpm_iap_start = 1; 
}

void init_native(void)
{
    msc_bulk_size = HS_BULK_EP_SIZE;
  
    udd_set_ep((NATIVE_EP_IN&0x0f), 1, USB_EP_TYPE_BULK, msc_bulk_size);
    udd_set_ep((NATIVE_EP_OUT&0x0f), 0, USB_EP_TYPE_BULK, msc_bulk_size);
    
    udd_ack_out_received(NATIVE_EP_OUT&0x0f);
    
    ping_pong.b_ping_flag = true;
    ping_pong.p_ping_buf_ptr = &(msc_bulk_buffer[0]);
    ping_pong.p_pong_buf_ptr = &(msc_bulk_buffer[PINGPONG_BUFFER_SIZE]);
    
    g_jpm_native_start = 1;
    
    blk_nbr = (sd_mmc_get_capacity(0) * 2);
    blk_size = SECTOR_SIZE;
}

void close_msc(void)
{ 
    udd_clr_ep(MSC_EP_IN&0x0f);
    udd_clr_ep(MSC_EP_OUT&0x0f);
    
    g_msc_start = 0;
}

void close_jpm(void)
{
    //udd_disable_endpoint_interrupt((IAP2_EP_IN&0x0f));
    //udd_disable_endpoint_interrupt((IAP2_EP_OUT&0x0f));
      
    udd_clr_ep(IAP2_EP_IN&0x0f);
    udd_clr_ep(IAP2_EP_OUT&0x0f);
    udd_clr_ep(INTR_EP_IN&0x0f);
    
    g_jpm_iap_start = 0;
    
    close_native();
}

void close_native(void)
{
    udd_clr_ep(NATIVE_EP_IN&0x0f);
    udd_clr_ep(NATIVE_EP_OUT&0x0f);
    
    g_jpm_native_start = 0;
}

bool jpm_setup(void)
{
     ep0_buf_ptr = NULL;
     max_ctrl_trans_length = 0;
     
     if((g_setup_req.bmRequestType & USB_REQ_DIR_MASK) == USB_REQ_DIR_IN)
     {
          if(g_setup_req.wLength == 0)
          {
              return false;
          }
     }
     
     switch(g_setup_req.bRequest)
     {
     case USB_REQ_GET_DESCRIPTOR:
       max_ctrl_trans_length = jpm_get_descriptor();
       if(max_ctrl_trans_length == 0)
       {
            return 0;
       }
       break;
       
      case USB_REQ_GET_STATUS:
       if(g_setup_req.wLength != 2)
       {
            return false;
       }
       if((g_setup_req.bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE)
       {
            ep0_buf_ptr = (uint8_t*)(&g_device_status);
       }
       else if((g_setup_req.bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDPOINT)
       {
            g_ep_status = Is_udd_endpoint_stall_requested((g_setup_req.wIndex & 0x000f));
            ep0_buf_ptr = (uint8_t*)(&g_ep_status);
       }
       else
       {
            return false;
       }
       max_ctrl_trans_length = 2;
       break;
       
     case USB_REQ_GET_CONFIGURATION:
       if(g_setup_req.wLength != 1)
       {
            return false;
       }
       
       ep0_buf_ptr = &g_config;
       
       max_ctrl_trans_length = 1;
       break;
       
     case USB_REQ_GET_INTERFACE:
       if(g_setup_req.wLength != 1)
       {
            return false;
       }
       
       if(g_config == 0)
       {
            return false;
       }
       
       if((uint8_t)(g_setup_req.wIndex & 0x00ff) > g_interface_num - 1)
       {
            return false;
       }
       
       if((g_setup_req.wIndex & 0x00ff) != 1)
       {
            return false;
       }
       ep0_buf_ptr = &g_alter_setting;
       
       max_ctrl_trans_length = 1;
       break;
       
     case USB_REQ_SET_ADDRESS:
       if(g_setup_req.wLength != 0)
       {
            return false;
       }
       
       max_ctrl_trans_length = 0;
       break;
       
     case USB_REQ_SET_CONFIGURATION:
       if(g_setup_req.wLength != 0)
       {
            return false;
       }
       
       if(!udd_get_configured_address())
       {
            return false;
       }
       
       
       
       if(g_setup_req.wValue > 1)
       {
            return false;
       }
       
       g_device_status = 0;       
       g_config = (uint8_t)(g_setup_req.wValue & 0x00ff);

       if(g_config == 1)
       {            
            if(ex_status.ex_power_type == P_SRC_PC)
            {
                init_msc();        
            }
            else
            {
                if(b_iOS6 == true)
                {
                    init_jpm_iOS6();
                }
                else
                {
                    init_jpm();
                }               
            }
            ex_status.usb_role = USB_CONFIGED;
       }
       else
       {
            if(ex_status.ex_power_type == P_SRC_PC)
            {
                close_msc();
            }
            else
            {
                close_jpm();
            }
            ex_status.usb_role = USB_ADDRESSED;
       }
       
       max_ctrl_trans_length = 0;
       
       break;
       
     case USB_REQ_SET_INTERFACE:
       if(g_setup_req.wLength != 0)
       {
            return false;
       }
       
       if(g_config == 0)
       {
            return false;
       }
       
       if((uint8_t)(g_setup_req.wIndex & 0x00ff) > g_interface_num - 1)
       {
            return false;
       }
       
       if((g_setup_req.wIndex & 0x00ff) != 1)
       {
            return false;
       }
       
       g_alter_setting = (uint8_t)(g_setup_req.wValue & 0x00ff);
       if(g_alter_setting == 1)
       {            
            init_native();
       }
       else
       {
            close_native();
       }
       
       max_ctrl_trans_length = 0;
       break;
       
      
     case USB_REQ_CLEAR_FEATURE:
       if((g_setup_req.wLength != 0) || ((g_setup_req.bmRequestType & USB_REQ_RECIP_MASK) != USB_REQ_RECIP_ENDPOINT))
       {
            return false;
       }  
       max_ctrl_trans_length = 0;  
       break;
       
     case USB_REQ_SET_FEATURE:
       if((g_setup_req.wLength != 0) || ((g_setup_req.bmRequestType & USB_REQ_RECIP_MASK) != USB_REQ_RECIP_ENDPOINT))
       {
            return false;
       }       
       max_ctrl_trans_length = 0;
       break;
     
     case USB_REQ_MSC_GET_MAX_LUN:
       if((g_setup_req.bmRequestType & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS)
       {
            return false;
       }
       
       if((g_setup_req.wLength != 1) || (g_setup_req.wValue != 0))
       {
            return false;
       }
       
       ep0_buf_ptr =&g_max_lun;
       max_ctrl_trans_length = 1;
       
       break;
       
     case USB_REQ_MSC_BULK_RESET:
       if((g_setup_req.bmRequestType & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS)
       {
            return false;
       }
       
       if((g_setup_req.wLength != 0) || (g_setup_req.wValue != 0))
       {
            return false;
       }
       
       max_ctrl_trans_length = 0;
       
       break;
       
     default:
       return false;
       break;
     }    
  
     return true;
}

static uint8_t jpm_get_strlen(uint8_t *buf)
{
    uint8_t  len = 0;

    while (*buf != NULL) 
    {
        len++;
        buf++;
    }

    return len;
}

static uint16_t jpm_make_str_desc(uint8_t *desc, uint8_t *unicode)
{
    uint8_t idx = 0;
    uint8_t len = 0;
  
    if (unicode != NULL) 
    {
        len =  jpm_get_strlen(unicode) * 2 + 2;  
        if(len > 64)       
        {
            unicode[63] = NULL;
        }
        desc[idx++] = len;
        desc[idx++] = USB_DT_STRING;
    
        while (*unicode != NULL) 
        {
            desc[idx++] = *unicode++;
            desc[idx++] = 0x00;
        }
    }
   
    return len;
}




